package mx.ipn.presentacion.reportes;

import com.trolltech.qt.core.*;
import com.trolltech.qt.gui.*;

import java.util.*;
import mx.ipn.to.ReporteTO;

public class ItemviewChart extends QMainWindow {

	private QAbstractItemModel model;

	/*
	 * public static void main(String args[]) { QApplication.initialize(args);
	 * 
	 * ItemviewChart mainW = new ItemviewChart(); mainW.show();
	 * 
	 * QApplication.exec(); }
	 */

	public ItemviewChart(ReporteTO[] arrReporteTO) {

		QMenu fileMenu = new QMenu(tr("&Archivo"), this);

		QAction openAction = new QAction(tr("A&brir..."), this);
		openAction.setShortcut(new QKeySequence(tr("Ctrl+B")));
		openAction.triggered.connect(this, "openFile()");
		fileMenu.addAction(openAction);

		QAction saveAction = new QAction(tr("&Guardar como..."), this);
		saveAction.setShortcut(new QKeySequence(tr("Ctrl+G")));
		saveAction.triggered.connect(this, "saveFile()");
		fileMenu.addAction(saveAction);

		QAction quitAction = new QAction(tr("&Salir"), this);
		quitAction.setShortcut(new QKeySequence(tr("Ctrl+S")));
		quitAction.triggered.connect(this, "close()");
		fileMenu.addAction(quitAction);

		setupModel();
		setupViews();

		menuBar().addMenu(fileMenu);
		statusBar();
		cargarReporteGenerado(arrReporteTO);
		// openFile("classpath:mx/ipn/presentacion/reportes/rpt/nuevoReporte.rpt");
		// openFile("classpath:mx/ipn/presentacion/empleado/ui/mande.rpt");

		setWindowTitle(tr("Módulo de Reportes y Estadisticas"));
		setWindowIcon(new QIcon(
				"classpath:mx/ipn/presentacion/recursos/iconos/target.png"));
		resize(650, 550);
	}

	private void setupModel() {
		model = new QStandardItemModel(8, 2, this);
		model.setHeaderData(0, Qt.Orientation.Horizontal, tr("Atributo"));
		model.setHeaderData(1, Qt.Orientation.Horizontal, tr("Cantidad/Valor"));
	}

	private void setupViews() {
		QSplitter splitter = new QSplitter();
		QTableView table = new QTableView();
		QAbstractItemView pieChart = new PieView(this);
		splitter.addWidget(table);
		splitter.addWidget(pieChart);
		splitter.setStretchFactor(0, 0);
		splitter.setStretchFactor(1, 1);

		table.setModel(model);
		pieChart.setModel(model);

		QItemSelectionModel selectionModel = new QItemSelectionModel(model);
		table.setSelectionModel(selectionModel);
		pieChart.setSelectionModel(selectionModel);

		setCentralWidget(splitter);
	}

	@SuppressWarnings("unused")
	private void openFile() {
		openFile("");
	}

	private void cargarReporteGenerado(ReporteTO[] arrReporteTO) {

		model.removeRows(0, model.rowCount(null), null);

		int x = 0;
		do {
			model.insertRows(x, 1, null);

			model.setData(model.index(x, 0, null), arrReporteTO[x]
					.getAtributo());
			model.setData(model.index(x, 1, null), arrReporteTO[x].getValor());
			model.setData(model.index(x, 0, null), new QColor(arrReporteTO[x]
					.getColor()), Qt.ItemDataRole.DecorationRole);
			x++;

		} while (x != arrReporteTO.length);

	}

	private void openFile(String path) {
		String fileName;
		if (path.equals(""))
			fileName = QFileDialog.getOpenFileName(this,
					tr("Seleccione la ubicación del Archivo"), "",
					new QFileDialog.Filter("*.rpt"));
		else
			fileName = path;

		if (!fileName.equals("")) {
			QFile file = new QFile(fileName);

			if (file.open(new QFile.OpenMode(QFile.OpenModeFlag.ReadOnly,
					QFile.OpenModeFlag.Text))) {
				QTextStream stream = new QTextStream(file);
				String line;

				model.removeRows(0, model.rowCount(null), null);

				int row = 0;
				do {
					line = stream.readLine();
					if (!line.equals("")) {

						model.insertRows(row, 1, null);

						String[] pieces = line.split(",");

						model.setData(model.index(row, 0, null), pieces[0]
								.trim());
						model.setData(model.index(row, 1, null), pieces[1]
								.trim());
						model.setData(model.index(row, 0, null), new QColor(
								pieces[2].trim()),
								Qt.ItemDataRole.DecorationRole);
						row++;

					}
				} while (!line.equals(""));

				file.close();
				statusBar().showMessage(
						String.format(tr("Cargado %s"), fileName), 2000);
			}
		}
	}

	@SuppressWarnings("unused")
	private void saveFile() {
		String fileName = QFileDialog.getSaveFileName(this,
				tr("Guardar Archivo Como:"), "",
				new QFileDialog.Filter("*.rpt"));

		if (!fileName.equals("")) {
			QFile file = new QFile(fileName);
			QTextStream stream = new QTextStream(file);

			if (file.open(new QFile.OpenMode(QFile.OpenModeFlag.WriteOnly,
					QFile.OpenModeFlag.Text))) {
				for (int row = 0; row < model.rowCount(null); ++row) {

					stream.writeString(model.data(model.index(row, 0, null),
							Qt.ItemDataRole.DisplayRole).toString()
							+ ",");
					stream.writeString(model.data(model.index(row, 1, null),
							Qt.ItemDataRole.DisplayRole).toString()
							+ ",");
					stream.writeString(((QColor) model.data(model.index(row, 0,
							null), Qt.ItemDataRole.DecorationRole)).name());

					stream.writeString("\n");
				}
			}

			file.close();
			statusBar().showMessage(String.format(tr("Saved %s"), fileName),
					2000);
		}
	}

	/*
	 * private void guardarNuevoReporte(ReporteTO[] arrReporteTO) { String
	 * fileName = "classpath:mx/ipn/presentacion/reportes/rpt/nuevoReporte.rpt";
	 * 
	 * if (!fileName.equals("")) { QFile file = new QFile(fileName); QTextStream
	 * stream = new QTextStream(file);
	 * 
	 * if (file.open(new QFile.OpenMode(QFile.OpenModeFlag.WriteOnly,
	 * QFile.OpenModeFlag.Text))) { for (int x = 0; x < arrReporteTO.length;
	 * x++) {
	 * 
	 * stream.writeString(arrReporteTO[x].getAtributo() + ",");
	 * stream.writeString(arrReporteTO[x].getValor() + ",");
	 * stream.writeString(arrReporteTO[x].getColor()); stream.writeString("\n"); } }
	 * 
	 * file.close(); // statusBar().showMessage(String.format(tr("Saved %s"), //
	 * fileName),2000); } }
	 */

	private class PieView extends QAbstractItemView {

		private int margin;
		private int totalSize;
		private int pieSize;
		private int validItems;
		private double totalValue;
		private QPoint origin;
		private QRubberBand rubberBand;

		public PieView(QWidget parent) {
			super(parent);
			horizontalScrollBar().setRange(0, 0);
			verticalScrollBar().setRange(0, 0);

			margin = 8;
			totalSize = 300;
			pieSize = totalSize - 2 * margin;
			validItems = 0;
			totalValue = 0.0;
		}

		protected void dataChanged(final QModelIndex topLeft,
				final QModelIndex bottomRight) {
			super.dataChanged(topLeft, bottomRight);

			validItems = 0;
			totalValue = 0.0;

			for (int row = 0; row < model().rowCount(rootIndex()); ++row) {

				QModelIndex index = model().index(row, 1, rootIndex());
				double value = toDouble(model().data(index));

				if (value > 0.0) {
					totalValue += value;
					validItems++;
				}
			}
			viewport().update();
		}

		protected boolean edit(final QModelIndex index, EditTrigger trigger,
				QEvent event) {
			return false;
		}

		public QModelIndex indexAt(final QPoint point) {
			if (validItems == 0)
				return null;

			int wx = point.x() + horizontalScrollBar().value();
			int wy = point.y() + verticalScrollBar().value();

			if (wx < totalSize) {
				double cx = wx - totalSize / 2;
				double cy = totalSize / 2 - wy;
				double d = Math.pow(Math.pow(cx, 2) + Math.pow(cy, 2), 0.5);

				if (d == 0 || d > pieSize / 2)
					return null;

				double angle = (180 / Math.PI) * Math.acos(cx / d);
				if (cy < 0)
					angle = 360 - angle;

				double startAngle = 0.0;

				for (int row = 0; row < model().rowCount(rootIndex()); ++row) {

					QModelIndex index = model().index(row, 1, rootIndex());
					double value = toDouble(model().data(index));

					if (value > 0.0) {
						double sliceAngle = 360 * value / totalValue;

						if (angle >= startAngle
								&& angle < (startAngle + sliceAngle))
							return model().index(row, 1, rootIndex());

						startAngle += sliceAngle;
					}
				}
			}

			return null;
		}

		protected boolean isIndexHidden(final QModelIndex index) {
			return false;
		}

		QRect itemRect(final QModelIndex index) {
			if (index == null)
				return new QRect();

			if (index.column() != 1)
				return new QRect();

			if (toDouble(model().data(index)) > 0.0) {
				return new QRect(margin, margin, pieSize, pieSize);
			}
			return new QRect();
		}

		QRegion itemRegion(final QModelIndex index) {
			if (index == null)
				return null;

			if (index.column() != 1)
				return null;

			if (toDouble(model().data(index)) <= 0.0)
				return null;

			double startAngle = 0.0;
			for (int row = 0; row < model().rowCount(rootIndex()); ++row) {

				QModelIndex sliceIndex = model().index(row, 1, rootIndex());
				double value = toDouble(model().data(sliceIndex));

				if (value > 0.0) {
					double angle = 360 * value / totalValue;

					if (sliceIndex.equals(index)) {
						QPainterPath slicePath = new QPainterPath();
						slicePath.moveTo(totalSize / 2, totalSize / 2);
						slicePath.arcTo(margin, margin, margin + pieSize,
								margin + pieSize, startAngle, angle);
						slicePath.closeSubpath();

						return new QRegion(slicePath.toFillPolygon()
								.toPolygon());
					}
					startAngle += angle;
				}
			}

			return null;
		}

		protected int horizontalOffset() {
			return horizontalScrollBar().value();
		}

		protected void mousePressEvent(QMouseEvent event) {
			super.mousePressEvent(event);
			origin = event.pos();
			if (rubberBand == null)
				rubberBand = new QRubberBand(QRubberBand.Shape.Rectangle, this);
			rubberBand.setRubberBandGeometry(new QRect(origin, new QSize()));
			rubberBand.show();
		}

		protected void mouseMoveEvent(QMouseEvent event) {
			QRect rect = new QRect(origin, event.pos()).normalized();
			rubberBand.setRubberBandGeometry(rect);
			super.mouseMoveEvent(event);

			QModelIndex underMouseIndex = indexAt(event.pos());
			if (underMouseIndex == null)
				setSelection(rect, selectionCommand(underMouseIndex, event));
			viewport().update();
		}

		protected void mouseReleaseEvent(QMouseEvent event) {
			super.mouseReleaseEvent(event);
			rubberBand.hide();
			viewport().update();
		}

		protected QModelIndex moveCursor(
				QAbstractItemView.CursorAction cursorAction,
				Qt.KeyboardModifiers modifiers) {
			QModelIndex current = currentIndex();

			switch (cursorAction) {
			case MoveLeft:
			case MoveUp:
				if (current.row() > 0)
					current = model().index(current.row() - 1,
							current.column(), rootIndex());
				else
					current = model().index(0, current.column(), rootIndex());
				break;
			case MoveRight:
			case MoveDown:
				if (current.row() < rows(current) - 1)
					current = model().index(current.row() + 1,
							current.column(), rootIndex());
				else
					current = model().index(rows(current) - 1,
							current.column(), rootIndex());
				break;
			default:
				break;
			}

			viewport().update();
			return current;
		}

		protected void paintEvent(QPaintEvent event) {
			QItemSelectionModel selections = selectionModel();
			QStyleOptionViewItem option = viewOptions();

			QBrush background = option.palette().base();
			QPen foreground = new QPen(option.palette().color(
					QPalette.ColorRole.WindowText));

			QPainter painter = new QPainter();
			painter.begin(viewport());
			painter.setRenderHint(QPainter.RenderHint.Antialiasing);

			painter.fillRect(event.rect(), background);
			painter.setPen(foreground);

			QRect pieRect = new QRect(margin, margin, pieSize, pieSize);

			if (validItems > 0) {

				painter.save();
				painter.translate(pieRect.x() - horizontalScrollBar().value(),
						pieRect.y() - verticalScrollBar().value());
				painter.drawEllipse(0, 0, pieSize, pieSize);
				double startAngle = 0.0;
				int row;

				for (row = 0; row < model().rowCount(rootIndex()); ++row) {

					QModelIndex index = model().index(row, 1, rootIndex());
					double value = toDouble(model().data(index));

					if (value > 0.0) {
						double angle = 360 * value / totalValue;

						QModelIndex colorIndex = model().index(row, 0,
								rootIndex());
						QColor color = (QColor) model().data(colorIndex,
								Qt.ItemDataRole.DecorationRole);

						if (currentIndex() != null
								&& currentIndex().equals(index)
								&& selections.isSelected(index))
							painter.setBrush(new QBrush(color,
									Qt.BrushStyle.Dense4Pattern));
						else if (selections.isSelected(index))
							painter.setBrush(new QBrush(color,
									Qt.BrushStyle.Dense3Pattern));
						else
							painter.setBrush(new QBrush(color));

						painter.drawPie(0, 0, pieSize, pieSize,
								(int) (startAngle * 16), (int) (angle * 16));

						startAngle += angle;
					}
				}
				painter.restore();
			}
			painter.end();
		}

		protected void resizeEvent(QResizeEvent event) {
			updateGeometries();
		}

		int rows(final QModelIndex index) {
			return model().rowCount(model().parent(index));
		}

		protected void rowsInserted(final QModelIndex parent, int start, int end) {
			for (int row = start; row <= end; ++row) {

				QModelIndex index = model().index(row, 1, rootIndex());
				double value = toDouble(model().data(index));

				if (value > 0.0) {
					totalValue += value;
					validItems++;
				}
			}

			super.rowsInserted(parent, start, end);
		}

		protected void rowsAboutToBeRemoved(final QModelIndex parent,
				int start, int end) {
			for (int row = start; row <= end; ++row) {

				QModelIndex index = model().index(row, 1, rootIndex());
				double value = toDouble(model().data(index));
				if (value > 0.0) {
					totalValue -= value;
					validItems--;
				}
			}

			super.rowsAboutToBeRemoved(parent, start, end);
		}

		public void scrollTo(final QModelIndex index, ScrollHint hint) {
			QRect area = viewport().rect();
			QRect rect = visualRect(index);

			if (rect.left() < area.left())
				horizontalScrollBar().setValue(
						horizontalScrollBar().value() + rect.left()
								- area.left());
			else if (rect.right() > area.right())
				horizontalScrollBar().setValue(
						horizontalScrollBar().value()
								+ Math.min(rect.right() - area.right(), rect
										.left()
										- area.left()));

			if (rect.top() < area.top())
				verticalScrollBar().setValue(
						verticalScrollBar().value() + rect.top() - area.top());
			else if (rect.bottom() > area.bottom())
				verticalScrollBar().setValue(
						verticalScrollBar().value()
								+ Math.min(rect.bottom() - area.bottom(), rect
										.top()
										- area.top()));

			update();
		}

		protected void setSelection(final QRect rect,
				QItemSelectionModel.SelectionFlags command) {
			QRect contentsRect = rect.translated(horizontalScrollBar().value(),
					verticalScrollBar().value()).normalized();

			int rows = model().rowCount(rootIndex());
			int columns = model().columnCount(rootIndex());
			Vector<QModelIndex> indexes = new Vector<QModelIndex>();

			for (int row = 0; row < rows; ++row) {
				for (int column = 0; column < columns; ++column) {
					QModelIndex index = model().index(row, column, rootIndex());
					QRegion region = itemRegion(index);

					if (region != null && region.intersects(contentsRect))
						indexes.add(index);
				}
			}

			if (indexes.size() > 0) {
				int firstRow = indexes.elementAt(0).row();
				int lastRow = indexes.elementAt(0).row();
				int firstColumn = indexes.elementAt(0).column();
				int lastColumn = indexes.elementAt(0).column();

				for (int i = 1; i < indexes.size(); ++i) {
					firstRow = Math.min(firstRow, indexes.elementAt(i).row());
					lastRow = Math.max(lastRow, indexes.elementAt(i).row());
					firstColumn = Math.min(firstColumn, indexes.elementAt(i)
							.column());
					lastColumn = Math.max(lastColumn, indexes.elementAt(i)
							.column());
				}

				QItemSelection selection = new QItemSelection(model().index(
						firstRow, firstColumn, rootIndex()), model().index(
						lastRow, lastColumn, rootIndex()));
				selectionModel().select(selection, command);
			} else {
				QModelIndex noIndex = null;
				QItemSelection selection = new QItemSelection(noIndex, noIndex);
				selectionModel().select(selection, command);
			}

			update();
		}

		protected void updateGeometries() {
			horizontalScrollBar().setPageStep(viewport().width());
			horizontalScrollBar().setRange(0,
					Math.max(0, totalSize - viewport().width()));
			verticalScrollBar().setPageStep(viewport().height());
			verticalScrollBar().setRange(0,
					Math.max(0, totalSize - viewport().height()));
		}

		protected int verticalOffset() {
			return verticalScrollBar().value();
		}

		public QRect visualRect(final QModelIndex index) {
			QRect rect = itemRect(index);
			if (rect.isValid())
				return new QRect(rect.left() - horizontalScrollBar().value(),
						rect.top() - verticalScrollBar().value(), rect.width(),
						rect.height());
			else
				return rect;
		}

		protected QRegion visualRegionForSelection(
				final QItemSelection selection) {
			int ranges = selection.size();

			if (ranges == 0)
				return new QRegion(new QRect());

			QRegion region = new QRegion();
			for (int i = 0; i < ranges; ++i) {
				QItemSelectionRange range = selection.at(i);
				for (int row = range.top(); row <= range.bottom(); ++row) {
					for (int col = range.left(); col <= range.right(); ++col) {
						QModelIndex index = model()
								.index(row, col, rootIndex());
						region = region.united(new QRegion(visualRect(index)));
					}
				}
			}
			return region;
		}
	}

	private double toDouble(Object o) {

		if (o instanceof String) {
			try {
				return Double.parseDouble((String) o);
			} catch (NumberFormatException e) {

			}
		}
		return 0;
	}
}
